home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / pcresrc / pcr8807.arc / LISTING1.ASM < prev    next >
Assembly Source File  |  1988-02-22  |  9KB  |  374 lines

  1. comment |
  2.    This program unravels DOS's memory control blocks (MCB's) and prints
  3.    the information it finds.  If it is run under DOS 3.0 or later, it
  4.    will also print the name of each program in memory when it can find
  5.    the name.
  6.  
  7.    Written for MASM 5.0
  8.    Save as  MEMLIST.ASM
  9.    Compile: MASM MEMLIST;
  10.            LINK MEMLIST;
  11.        |
  12.  
  13.  
  14. LF    equ    0ah        ;Linefeed character
  15. CR    equ    0dh        ;Carriage return character
  16. STDOUT    equ    1
  17.  
  18. PRINT    macro    text
  19.     mov    ah,40h        ;Write to file/device
  20.     mov    bx,STDOUT    ;Message to standard output
  21.     lea    dx,&text&msg    ;DS:DX ==> message
  22.     mov    cx,&text&len    ;CX = message length
  23.     int    21h
  24.     endm
  25.  
  26. EXIT    macro    val
  27.     mov    ah,4ch        ;Exit from program
  28.     mov    al,val        ;Return value
  29.     int    21h
  30.          endm
  31.  
  32.     .MODEL SMALL
  33.     .STACK
  34.     .DATA
  35. ourpid    dw    ?
  36. maxmem    dw    ?
  37. basepsp    dw    ?
  38. DosVer    dw    ?
  39. DosV3    db    0
  40.  
  41. NoV1msg    db    'This program cannot be used with DOS v. 1.x',CR,LF
  42. NoV1len    equ    $-NoV1msg
  43.  
  44. VERmsg    db    "Unknown DOS version -- can't find start of memory chain."
  45.     db    CR,LF
  46. VERlen    equ    $-VERmsg
  47.  
  48. LERRmsg    db    "There is an apparent error in this program's MCB",CR,LF
  49. LERRlen    equ    $-LERRmsg
  50.  
  51. ERRmsg    db    'Memory Allocation Error.  Illegal MCB found.',CR,LF
  52. ERRlen    equ    $-ERRmsg
  53.  
  54. HDRmsg    db    CR,LF,CR,LF
  55.     db    '  MCB     Block   Block   Block   Block   Process',CR,LF
  56.     db    '  Seg     Seg     Owner   Size    Type    Name   ',CR,LF
  57.     db    '  -----------------------------------------------',CR,LF
  58. HDRlen    equ    $-HDRmsg
  59.  
  60. mcbmsg    db    '  '
  61. mcbadr    db    '0000    '
  62. blkadr    db    '0000    '
  63. blkown    db    '0000    '
  64. blksiz    db    '0000    '   
  65. mcblen    equ    $-mcbmsg
  66.  
  67. CRLFmsg    db    CR,LF
  68. CRLFlen    equ    $-CRLFmsg
  69.  
  70. PRGmsg    db    'Prog    '
  71. PRGlen    equ    $-PRGmsg
  72. ENVmsg    db    'Envr.   '
  73. ENVlen    equ    $-ENVmsg
  74. OTHmsg    db    'Data?   '
  75. OTHlen    equ    $-OTHmsg
  76.  
  77. hexlist    db    '0123456789ABCDEF'
  78.  
  79. memMSG    db    CR,LF
  80.     db    'Top of memory: '
  81. memSIZ    db    '0000',CR,LF
  82.     db    'Next program will load at '
  83. memLOC    db    '0000',CR,LF
  84.     db    'Memory available: '
  85. memAVL    db    '00000h bytes.',CR,LF
  86. memlen    equ    $-memMSG
  87.  
  88.  
  89.     .CODE
  90. start:     cld
  91.     mov    ax,@data
  92.     mov    ds,ax        ;Bring DS to our data segment
  93.     mov    ah,30h        ;DOS function: GetVersion
  94.     int    21h        ;Call DOS
  95.     mov    DosVer,ax    ;Save full version number
  96.     cmp    al,2        ;At least version 2?
  97.     jae    verOK        ;Go if okay
  98.     PRINT    noV1        ;Else print error
  99.     EXIT    -1
  100. verOK:    sub    al,2        ;Test if version 3
  101.     mov    DosV3,al    ;Save result (0 or 1)
  102.  
  103.     mov    bx,2        ;PSP:2 contains maxmem
  104.     mov    ax,es:[bx]
  105.     mov    maxmem,ax
  106.     push    es
  107.     mov    ax,es        ;Get addr. of our PSP
  108.     mov    ourpid,ax    ;Save it
  109.     dec    ax        ;Point to our MCB
  110.     mov    es,ax        ;Now ES ==> our MCB
  111.     mov    bx,1        ;Offset to PID in our MCB
  112.     inc    ax        ;AX contains our PID again
  113.     cmp    ax,word ptr es:[bx]
  114.     jz    okay        ;If not the same, something's wrong!
  115.     PRINT    LErr
  116.     EXIT    -1
  117.  
  118. okay:    pop    es        ;ES ==> our PSP
  119.     call    FindStart    ;Find head of list
  120. ;----------
  121. ;  ES now points to lowest PSP in memory,
  122. ;  which should belong to the first (and possibly only)
  123. ;  copy of command.com.  We'll use its MCB to start the
  124. ;  trek through memory
  125. ;----------
  126.     PRINT    HDR        ;Table headers
  127. rB1:    push    es        ;Save ES
  128.     call    printMCB    ;Print block info
  129.     mov    ax,es        ;MCB segment in AX
  130.     inc    ax        ;AX has block segment
  131.     mov    es,ax        ;ES ==> memory block
  132.     call    printType    ;Print block type
  133.     jc    rB2        ;Go if not ENV
  134.     test    DosV3,-1    ;Using version 3 or later?
  135.     jz    rB2        ;Go if not
  136.     call    printCmd    ;Yes -- look for proc. name
  137. rB2:    print    CRLF        ;Terminate info line
  138.     pop    es        ;ES ==> current MCB
  139.     mov    bx,0        ;ES:BX ==> block type (M or Z)
  140.     cmp    byte ptr es:[bx],'Z'  ;At an end?
  141.     jz    rB3        ;Yes -- go
  142.     mov    ax,es        ;Get this MCB segment
  143.     inc    ax        ;AX has block segment
  144.     mov    bx,3        ;ES:BX ==> block size
  145.     add    ax,es:[bx]    ;Add block size
  146.     mov    es,ax        ;ES ==> next MCB
  147.     jmp    rB1        ;Loop back
  148.  
  149. rb3:    call    printMEM    ;Print memory info
  150.     EXIT    0
  151.  
  152. ;---------
  153. ;  Find the start of the MCB list.
  154. ;  This is the trickiest part of the program, since it is
  155. ;  rarely documented.
  156. ;---------
  157.  
  158. findStart    proc    near
  159.     mov    ax,0            ;Start with segment 0
  160.     mov    es,ax            ;  in ES
  161.     mov    bx,0c3h            ;Find segment of resident DOS
  162.     mov    ax,es:[bx]        ;  and put in AX
  163.     mov    es,ax            ;ES ==> resident DOS segment
  164.     mov    ax,DosVer        ;Get DOS version again
  165.     xchg    ah,al            ;Major version in AH, minor in Al
  166.     mov    bx,10ah            ;Offset for 2.0
  167.     cmp    ax,0209h        ;Version 2.0?
  168.     jbe    fS2            ;Yes -- BX has right offset
  169.     mov    bx,0F6h            ;Offset for 2.1
  170.     cmp    ax,0213h        ;Version 2.10 - 2.19 ?
  171.     jbe    fS2            ;Yes -- BX is correct, go
  172.     cmp    al,2            ;Is it version 2?
  173.     jne    fS1            ;No -- go
  174.     PRINT    VER            ;Else print error
  175.     EXIT    -1            ;  and exit
  176.  
  177. fs1:    mov    bx,128h            ;Offset for 3.0
  178.     cmp    ax,0309h        ;Version 3.0?
  179.     jbe    fS2            ;Yes -- go
  180.     mov    bx,22h            ;Offset for 3.1 to 3.3
  181. fS2:    les    bx,es:[bx]        ;Get first memory block
  182.     ret
  183. findStart    endp
  184.  
  185. comment    |
  186. ;---------
  187. ;  This is an alternate method of finding the start of the MCB list.
  188. ;  This method will only trace back to the last copy of Command.Com
  189. ;  installed in memory, but otherwise should work if the above method
  190. ;  doesn't agree with your version of MS-DOS
  191. ;---------
  192.  
  193. findStart    proc    near
  194.     mov    bx,16h        ;PSP:16h ==> parent's PSP
  195. fS1:    mov    ax,es:[bx]    ;Get parent's PSP addr.
  196.     cmp    ax,0        ;At end of chain? (1st test)
  197.     jz    fS2        ;Yes -- go
  198.     cmp    ax,basepsp    ;At end of chain? (2nd test)
  199.     jz    fS2        ;Yes -- go
  200.     mov    basepsp,ax    ;Else save this value
  201.     mov    es,ax        ;ES ==> parent PSP
  202.         jmp    fS1        ;And loop back
  203. fS2:    mov    ax,es        ;Get PSP segment
  204.     dec    ax        ;AX = segment of MCB
  205.     mov    es,ax        ;ES ==> 1st MCB
  206.     ret
  207. findStart    endp
  208.     |
  209.  
  210. ;---------
  211. ;  ES ==> an MCB.  Print info contained in MCB
  212. ;---------
  213.  
  214. printMCB     proc    near
  215.     mov    ax,es        ;AX = MCB segment
  216.     lea    di,mcbadr    ;DI => message area
  217.     call    hextoasc    ;Convert AX to ASCII
  218.     inc    ax        ;AX = block address
  219.     lea    di,blkadr
  220.     call    hextoasc
  221.     mov    bx,0        ;Is this really a block?
  222.     mov    al,es:[bx]    ;Get first byte
  223.     cmp    al,'M'        ;In the chain?
  224.     je    pM1        ;Yes -- go
  225.     cmp    al,'Z'        ;Last of chain?
  226.     je    pM1        ;Yes -- go
  227.     PRINT    ERR        ;Else report error
  228.     EXIT    -1        ;End immediately
  229.  
  230. pM1:    mov    bx,1        ;ES:BX ==> block PID
  231.     mov    ax,es:[bx]    ;Get PID
  232.     lea    di,blkown
  233.     call    hextoasc
  234.     mov    bx,3        ;ES:BX ==> Block size
  235.     mov    ax,es:[bx]    ;Get size in AX
  236.     lea    di,blksiz
  237.     call    hextoasc
  238.     PRINT    mcb
  239.     ret
  240. printMCB     endp
  241.  
  242.  
  243. ;---------
  244. ;  ES ==> a memory block.  Is it a PSP, an ENV, or ??? block?
  245. ;  Notice that the test for PSP is whether the 1st 4 bytes are ASCII,
  246. ;  so a data block may show up as a PSP
  247. ;---------
  248.  
  249. printTYPE     proc    near
  250.     mov    bx,0            ;ES:BX ==> beginning of block
  251.     cmp    byte ptr es:[bx],0CDh    ;PSPs always start CD hex
  252.     jnz    typ1            ;Not here -- go
  253.     PRINT    PRG
  254.     stc                ;Set carry as flag
  255.     ret
  256.  
  257. typ1:    mov    cx,4            ;Try 4 characters
  258. typ2:    mov    al,es:[bx]        ;Get a byte
  259.     cmp    al,' '            ;Control code?
  260.     jb    typ3            ;Yes -- go
  261.     cmp    al,'a'            ;Lowercase?
  262.     jae    typ3            ;Yes -- go
  263.     inc    bx            ;Else point to next
  264.     loop    typ2            ;And try again
  265.     PRINT    ENV            ;It must be an ENV
  266.     clc                ;Clear carry as flag
  267.     ret
  268.  
  269. typ3:    PRINT    OTH            ;Can't tell what it is
  270.     stc                ;Set carry as flag
  271.     ret
  272. printTYPE    endp
  273.  
  274. ;---------
  275. ;  ES==> a environment segment.  Scan the segment and print the 
  276. ;  name of the program that owns this environment.  This will only work
  277. ;  with DOS version 3.0 and later.
  278. ;---------
  279.  
  280. printCMD    proc    near
  281.     push    ds            ;Save data segment
  282.     push    es            ;Copy ES
  283.     pop    ds            ;  to DS
  284.     mov    si,0            ;DS:SI ==> environment text
  285.     mov    cx,8000h        ;Maximum len. of environment
  286.     mov    ax,0            ;Initialize register for search
  287. pC1:    lodsb                ;Get a byte in AL, incr. SI
  288.     or    ax,ax            ;Anything in AX?
  289.     jz    pC2            ;No -- found beginning of CMD
  290.     mov    ah,al            ;Else keep byte
  291.     loop    pC1            ;And look at the next
  292. pC1a:    pop    ds            ;Not found 
  293.     ret                ;  -- return
  294.  
  295. pC2:    lodsw                ;Get next word in AX
  296.     cmp    ax,1            ;Should be 0001
  297.     jne    pC1a            ;No -- go
  298.     mov    dx,si            ;Keep addr. of beginning
  299.     mov    cx,0            ;Ready to count length
  300. pC3:    lodsb                ;Get next byte, incr SI
  301.     inc    cx            ;Count the byte
  302.     cmp    al,' '            ;End of string?
  303.     ja    pC3            ;No -- keep looking
  304.     mov    bx,STDOUT        ;Else we're ready to print
  305.     mov    ah,40h            ;Write to file/device
  306.     int    21h            ;Print the command
  307.     pop    ds            ;Recover data pointer
  308.     ret
  309. printCMD    endp
  310.  
  311. ;---------
  312. ;  Print memory information
  313. ;---------
  314.  
  315. printMEM    proc    near
  316.     mov    ax,maxmem
  317.     lea    di,memSIZ
  318.     call    hextoasc
  319.     mov    ax,ourpid
  320.     lea    di,memLOC
  321.     call    hextoasc
  322.     mov    ax,maxmem
  323.     sub    ax,ourpid
  324.     lea    di,memAVL
  325.     call    hextoasc
  326.     PRINT    mem
  327.     ret
  328. printMEM    endp
  329.  
  330. ;---------
  331. ;  Transfer the value in AX as ASCII-Hex to the location at DS:DI
  332. ;  Only DI can be altered
  333. ;---------
  334.  
  335. hextoasc    proc    near
  336.     push    ax           ;Save registers
  337.     push    bx        
  338.     push    cx
  339.     push    es        ;Save ES register
  340.     push    ds        ;Copy DS
  341.     pop    es        ;  to ES
  342.     lea    bx,hexlist    ;DS:BX ==> list of Hex characters
  343.  
  344.     xchg    ah,al        ;Swap bytes
  345.     call    hexbyte        ;Do one byte
  346.     xchg    ah,al        ;Put bytes back
  347.     call    hexbyte        ;Do the next
  348.     pop    es        ;Restore registers
  349.     pop    cx
  350.     pop    bx
  351.     pop    ax
  352.     ret
  353.  
  354. hexbyte        proc    near
  355.     push    ax        ;Save AL
  356.     and    al,0F0h        ;Mask off low nibble
  357.     mov    cl,4        ;bits to shift
  358.     shr    al,cl        ;Move high bit low
  359.     xlat            ;Get HEX byte in AL
  360.     stosb            ;Put it at ES:DI, incr DI
  361.     pop    ax        ;Recover AL
  362.     push    ax        ;Save AX again
  363.     and    al,0Fh        ;Mask off high nibble
  364.     xlat            ;Get hex byte in AL
  365.     stosb            ;Put in string
  366.     pop    ax
  367.     ret
  368. hexbyte        endp
  369. hextoasc    endp
  370.  
  371.     end    start
  372.  
  373.  
  374.